package threading;



// 就不写泛型了, 就直接写朴素的代码. 假定存储的元素是 int.
// 基于数组来实现队列.

//模拟实现堵塞队列

/**
 * 需要三步模拟实现堵塞队列
 * 1. 模拟实现普通的队列
 * 2. 加上线程安全
 * 3. 加上堵塞功能
 */
public class ThreadDemo21BlockingQueueImplement {
    private int[] elem = new int[1000];

    // 约定 [head, tail) 是队列 的有效元素
    //有很多的读操作，加上volatile 可以保证内存可见性（多线程条件下，编译器对于代码的优化，产生了误判，从而导致了bug）
    volatile private int head = 0; //不初始化也默认是0
    volatile private int tail = 0;
    volatile private int size = 0;

    //入队列
    //在此相当于this加锁，加锁对象就是ThreadDemo21BlockingQueueImplement new 出来的对象
    synchronized public void put(int value) throws InterruptedException {
        //入队列需要判断是否满了,满了
//        if(size == elem.length) {
//            //return;
//            //这里加上堵塞效果
//            this.wait(1000);  //锁的是谁，谁就使用wait操作
//        }
        while (size == elem.length) {
            //return;
            //这里加上堵塞效果
            this.wait(1000);  //锁的是谁，谁就使用wait操作
        }
        elem[tail] = value;
        tail++;
        if(tail == elem.length) {
            tail = 0;
        }
        //tail = tail % elem.length;   注意这种写法也是可以的，不过不便于理解，可读性不高，
        //                             也就是不好维护，不如上面的写法
        size++;
        this.notify();
    }

    //出队列
    synchronized public Integer take() throws InterruptedException {
        /**
        if (elem == null) {
            return null;
         */
//        if(size == 0) {
//            this.wait(1000);
//        }
        while(size == 0) {  //更好的是写成while
            this.wait(1000);
        }
        int value = elem[head];
        head++;
        if(head == elem.length) {
            head = 0;
        }
        size--;
        //出的时候唤醒wait
        this.notify();
        return value;   //快捷键 crtl + alt + t    surround快捷代码


    }
}
